50 — Baking 并导出场景

Three.js Journey · Bruno Simon · 难度:简单

50 — Baking 并导出场景 课程海报

简介

我们创建了一个在做渲染时看起来不错的场景,但我们的最终目标是把它导出到 Three.js。

我们需要对它进行优化,同时也要对它进行 bake。如果你还记得上一课的内容,baking 就是把看起来很好的渲染结果保存到一张 texture 中,然后我们再把这张贴到 Three.js 里的 geometry 上。因此,我们需要对场景进行 UV 展开(unwrap)。

准备工作

你可以从上一课制作的 Blender 文件开始,也可以使用 starter 文件来获得与那一课完全相同的文件。

优化

移除隐藏的面

我们需要做的第一件事就是移除所有隐藏的面。这指的是直接位于地板上的面,比如树干的底部。同时,它也指与其他面贴合的面,比如楼梯台阶的背面。

为了更清楚地看到这些面,我们可以在 Wireframe 和 Solid 着色模式之间切换:

树干

我们先从树干开始。

你可以在 Outliner 中取消勾选,来停用此刻不需要处理的集合:

要优化树干和原木:

你应该会得到类似这样的结果:

栅栏

对栅栏重复同样的操作:

柱灯

对柱灯重复同样的操作。你只需要处理其中一个柱灯,因为它们是关联副本(linked duplicates)。

别忘了删除主梁的底部封盖以及绳子的封盖:

石头

对石头重复同样的操作:

虽然不是必须的,但如果有些石头伸进了地面里,你可以用上一课用过的 bissect 工具来修复。在 Edit Mode 下选中所有面,按 F3 并搜索 bissect。然后切掉你想要裁去的、伸出来的那部分石头。

传送门

对于传送门来说,大部分优化都涉及楼梯。

你可以先调整它们的大小,让它们不要重叠太多:

然后你可以移除底部的面,以及台阶之间被隐藏的面:

如果你完全按照我说的完成了前面的课程,那么现在当你尝试移除楼梯内部砖块的面时,你会发现无法只编辑某个砖块,因为它们都是关联副本,只能同时编辑所有砖块。

如果你没有使用关联副本,就不应该遇到这个问题,不过无论如何我们都要确保场景中没有任何对象是关联副本。

解除副本关联

我们需要解除副本的关联,以便修复砖块,同时也是为了下一步——也就是展开 geometry。如果我们保留这些关联,两个柱灯就会展开到相同的坐标上。这会导致 baking 在同一处贴图位置上被做两次。

要解除副本关联,进入 Object Mode,用 A 选中所有对象。即使我们只关心传送门的砖块和柱灯,我们执行的操作应用到整个场景也没有任何副作用。

在所有对象都被选中的情况下,按 F3 并搜索 make single。然后选择 Make Single User > Object & Data:

所有之前的关联副本现在都已解除关联,我们就可以在不改动全部砖块的情况下,编辑与楼梯重叠的砖块了。

移除楼梯内部砖块的面:

检查整个场景,确保你已经删完了所有隐藏的面。

漏掉一些不是什么大问题,你以后仍然可以删除它们。但一旦我们开始展开 geometry,那时候再移除面可能会带来一些后果。

修正面的朝向

有一个我们看不见的问题与面的朝向有关。所有面都有正面和背面。虽然这在渲染时不是问题,但它可能会在 baking 过程中造成 bug,一些面可能会变黑。而且这些面在 Three.js 中根本不会被渲染,因为默认情况下背面是隐藏的。

你可能已经猜到,这个朝向与 normal(法线)有关。在做 extrude、inset 以及其他类似操作时,我们可能无意间翻转了 normal。

首先,我们需要一种查看面朝向的方法。在 Object Mode 下,在 Blender Viewport 3D 的右上角,点击下面这个图标:

在弹出的菜单中,勾选 Face Orientation:

现在,当朝向正确时你应该会看到蓝色的面,朝向错误时会看到红色的面:

在这个例子中只有柱灯是错的,但你的模型可能会得到截然不同的结果。

如果一切都是蓝色的,那么恭喜你,你可以跳过这一步。

要修正红色的面:

一旦整个场景都变成蓝色,你就可以取消勾选 Face Orientation 并继续:

归一化缩放

另一个问题和缩放有关。

有些对象是在 Edit Mode 下被缩放的,这意味着我们缩放的是 geometry,而不是对象本身。另一些对象则是在 Object Mode 下被缩放的,这意味着对象上有一个变换,但 geometry 本身没有。

同样,在做渲染时这并不是很重要。但它在做 UV 展开时可能会引发问题。

在本课后面,我们将使用自动 UV 展开,而 Blender 会考虑 geometry 的大小,但不会考虑对象的缩放。这可能会导致一些对象占用过多或过少的空间。例如,你可能最终让斧头只占据贴图的一半,因为尽管我们缩小了对象缩放,geometry 本身仍然很大。

要修复这个问题,我们需要归一化所有缩放。

在 Object Mode 下,用 A 选中所有对象,按 CTRL + A 打开 Apply 菜单并选择 Scale:

你看不出任何区别,但所有对象的缩放都被应用到了它们的 geometry 上。这样一来,我们所有对象的缩放现在都是 1。

优化到此结束,我们可以开始对场景进行 UV 展开了。

别忘了保存。

UV 展开

思路是把构成我们场景的所有 geometry 展开到一个正方形里。之后,这将使我们能够把渲染 bake 到一张贴图上,而这张贴图会遵循我们设定的展开方式。

场景:

展开后的场景:

展开 geometry 有多种方法。我们可以使用一个“智能”的自动版本,它会做得相当不错。或者,我们可以手动展开来得到一个更优化的版本,但代价是更多的精力。

我们将根据对象的不同,混合使用这两种技巧。

首先,我们可以把右下角的区域改成 UV Editor:

UV Editor 会显示一个代表我们展开结果的正方形。我们需要让所有东西都放进这个正方形里。我们本可以使用多张贴图,也就是独立的 UV 展开,但我们的场景并没有那么复杂或庞大。

地板

我们先从最简单的元素——地板开始展开。

正如你在 UV Editor 中看到的,这个平面已经被展开,并且占据了整个 UV。默认情况下,Blender 会为大多数基础几何体生成 UV 坐标。这很好,我们可以简单地把这个正方形移到 UV 贴图的一个角落里。

要编辑 UV,快捷键几乎和编辑对象一样。将鼠标悬停在 UV Editor 区域时,按 A 选中全部,按 S 缩放,按 G 移动:

不要在精确放置上花太多时间。最后我们会重新整理这些东西。

栅栏

我们来尝试一个更难的形状,展开栅栏。

如你所见,geometry 已经被展开了,但构成栅栏的 4 个盒子一个叠一个,呈十字形,与我们 geometry 的比例并不吻合。这是立方体的默认 UV 展开结果。我们需要自己来展开它。

我们先专注于栅栏的其中一根柱子。要选中一根柱子,点击其中一个面:

按 CTRL + L,这根柱子的所有其他面现在应该都被选中了(确保在弹出的、位于区域左下角的菜单中 Seam 是激活的:

这个技巧对于选中我们所说的 island(岛)非常有用。一个 island 就是一组彼此相连的面。

要展开这根柱子,按 U 并选择 Unwrap:

遗憾的是,这并不是一个好的展开:

这是因为我们没有提供关于如何“切开”geometry 的信息。

如果你尝试展开一个立方体而不切开一些边,你最终会得到一团糟。这些切口叫做 seams(缝合线)。

要创建一条 seam,进入 Edge 选择模式,然后选中你希望在展开时被切开的边:

按 U 并选择 Mark seam:

如果你取消选中所有东西,你会看到这些 seam 现在变成了红色:

如果你的 seam 没问题,就不要去动它们,但要知道如果有需要,你是可以移除它们的。要移除(如果你不需要,就别这么做),选中相关的边,按 U 并选择 Clear Seam:

找到在哪里切开 geometry 可能非常困难。你必须预判结果并不断尝试,直到成功为止。只要确保面没有变形就好。

再次选中整根柱子(选中一部分,按 CTRL + L 选中整个 island),按 U 并选择 Unwrap 再次展开它:

如你所见,这次展开好多了。

我们对另一根柱子做同样的操作。选中相同的边,按 U 并选择 Mark Seam:

然后选中整根柱子,按 U 并选择 Unwrap:

你应该会得到相同的结果。两根柱子的展开结果重叠在一起,但我们稍后会修复。现在,我们只应专注于把 seam 设置正确。

用同样的方式切开其中一块木板:

展开它:

这一次,与其对另一块木板做同样的操作,不如直接删除下面那块,复制上面那块(已经展开好的),然后把它放到下面那块的位置:

这只是一种节省时间的方法。

现在栅栏的各个不同部分都用 seam 切好了,选中所有 geometry,按 U 再次执行展开:

展开看起来很棒,可惜这些 island 彼此靠得太近了。当我们进行 baking 时这会成为问题,因为 baking 会稍微溢出一点。我们需要把它们分开。

当你选择 Unwrap 时,区域左下角会弹出一个小菜单(如果你错过了那个菜单,就再展开一次):

在这里,你可以修改 Margin。把它稍微增大到 0.15 左右:

如你所见,这些 island 现在稍微分开了。

在把这些 UV 坐标移到贴图某处之前,我们需要处理其他的栅栏。

与其切开并展开所有的栅栏,我们可以直接删除之前那些,然后把展开好的那个复制到它们的位置上。不要在精确定位上花太多时间。

在 Object Mode 下,用 SHIFT + D 复制展开好的栅栏,并替换其他的。

现在选中所有栅栏,进入 Edit Mode,选中所有面并再次展开它们,不过这一次是把它们放在一起展开。

你应该把 Margin 改成 0.065 左右:

(你可能注意到了,上面的截图里有更多的 island。这是因为我在同一个位置复制了其中一个栅栏导致的一个错误。忽略它。)

把这些展开结果放到 UV 贴图的一个角落里:

同样,精确位置并不重要,我们稍后会重新整理所有东西。

分离 Emission 材质

我们将对柱灯重复整个过程,但在这么做之前,我们需要分离出发光的对象。

我们这么做是因为不想 bake 这些对象。毕竟它们都是纯色,我们会在 Three.js 中创建 material 来给它们赋予这些颜色。

我们本可以 bake 这些对象,但那样会浪费贴图空间。

创建一个 emissions 集合,把两盏灯和传送门(只包含发光部分)放进去:

把这个集合设为不可选中,这样我们在做 baking 时就不会选中它们:

柱灯

现在我们可以展开柱灯了。

和栅栏一样,先只处理一个,等你满意后,把它复制并放到另一个柱灯的位置上。

为了帮助你专注于你想展开的对象,你可以选中它,然后按小键盘上的 /。这会把它隔离出来:

如果你想退出这种隔离状态,再按一次 /。

你可以自己尝试展开。慢慢来,这是个漫长的过程。但随着时间推移,你就能又快又高效地完成它。

你得到的结果可能会和课程里不一样,这完全正常。展开的方法有很多很多种,而且我们其实还不知道自己是不是犯了错。尽你所能就好,不要害怕切得太多。

以下是我的做法:

灯罩的切割尤其困难。在这里,我决定只做一条从底部向上的切口。这并不总是一个好主意,因为如你所见,展开后它会造成一些变形:

但也没那么糟,至少我们减少了 island 的数量。

展开结果看起来是这样的:

在重新整理这些 island 之前,我们可以把柱子复制到另一根的位置上,然后把它们一起展开:

由于这些 island 是弯曲的,Blender 摆放得不太好。稍微优化一下摆放位置,把它们放到 UV 贴图的另一个角落。始终要确保在它们之间留出一些空间:

传送门

对传送门应用相同的流程。隔离每个对象,添加 seam,通过展开来测试结果,等你处理完传送门的所有部分后,把它们全部选中并展开所有东西。

这是楼梯:

这些是砖块:

这是整个传送门:

石头

别担心,我们不会自己切开它们。即使我们这么做了,那也会花费很长时间,而且最终会得到扭曲的展开结果。相反,我们将使用一个自动的“智能”展开。

确认弹出的窗口(我们随后可以访问相同的参数):

这就是你的自动展开结果:

把 Islands Margin 增大到 0.025 左右,在 island 之间留出一些空间。

遗憾的是,我们已经用完了贴图的所有角落。目前,先把这些展开结果移出贴图。这不是问题,因为最后我们会重新整理所有东西。

如你所见,自动展开的效果还不错。我们本可以把这种技术用于整个场景。但是,自己做展开能让我们通过减少 island 数量和减少 seam 来进一步优化。这也是把不同的 island 组分开保持的好方法。如果我们决定移除某个对象,这会很方便。我们就能腾出完整的区域用于更多的展开。

树干、原木和斧头

切开树干。别忘了还要为每根树干环绕一圈的年轮加一条切口。

切开原木:

切开斧头:

把它们全部(树干、原木和斧头)一次性展开,并把它们放到 UV 贴图之外的地方:

重新整理

就是这样,我们已经展开了整个场景。

然而目前,各组 island 散布在整个 UV 贴图上,甚至还在贴图之外。

选中所有已展开的对象(不包含 emissions 对象)。然后进入 Edit Mode 并选中所有面,以便预览当前的 UV 展开:

如果你没有看到这个,或者你看到了重叠的展开,试着找出是哪个对象出了问题并修复它。你也可能漏掉了一些对象。

在尝试让所有东西都放进 UV 贴图之前,我们需要确保不同组之间的比例是一致的。我们不希望某个对象占据比它实际需要更小或更大的空间。

使用 UV Editor 右上角的下面这个图标(如果你看不到,就把区域放大):

在弹出的菜单中,勾选 Display Stretch 并把它改成 Area:

对于某些较旧的 Blender 版本,这个选项可能在别的位置。如果你右上角有一个 Display 按钮,打开它,你应该能找到一个 stretch 或 stretching 复选框。如果都没有,用 N 打开侧边栏(如果还没打开的话),然后到 view 标签页里找那个复选框。

现在你可以通过颜色来判断某个 island 占用的面积是比其他大还是小:

缩放不同的部分,直到所有东西的颜色都相似。颜色可能与我的不同。

现在是把所有东西都放进 UV 贴图的时候了。这里一个非常重要的步骤是,同时听《俄罗斯方块》主题曲。

几个技巧:

一旦你对结果满意,就可以停用 Display Stretch:

Baking

现在我们的场景已经很好地展开了,我们可以开始对它进行 bake。

创建贴图

首先我们需要在 Blender 中创建一张贴图,我们可以使用 UV Editor 区域来管理这张图像。

退出 Edit Mode。在区域顶部,你应该有一个 + New 按钮:

点击它打开 New Image 菜单:

使用以下参数:

Name

使用 baked。

叫什么都行,但我们只会有一张贴图,而且它要包含“baked”的贴图。

Width and Height

使用 4096。

我们使用 2 的幂次大小,因为这张贴图将会在 Three.js 中使用。4096 已经很大了,但我们想要好的质量。8192 的贴图可能无法在所有浏览器上工作。

Color

使用白色。

这并不是很重要,但在 Three.js 中,从特定角度看模型时,mip mapping 可能会让这个颜色出现在 geometry 的边缘上。白色的色调看起来会像反光,用户不会注意到它。

Alpha

不勾选。

我们的贴图不需要 alpha。

Generated Type

使用 Blank。

我们希望初始贴图就是我们上面选择的颜色。其他选项会创建网格,可以用来查看贴图在 geometry 上的样子,但我们不需要那个。

32-bit Float

勾选。

这是一个非常重要的部分,我们稍后会解释。

Tiled

不勾选。

我们不需要贴图重复自身。

以下是最终的设置:

确认它,你的 UV 贴图背景现在应该使用这张图像了。如果看不到贴图的边缘,就缩小视图:

注意,你可以把任何贴图显示为 UV Editor 的背景。这里的目的就是帮助你同时看到 UV 映射和贴图。

保存贴图

在往贴图里 bake 任何东西之前,我们先把它保存到某个地方。这其实不是必须的,贴图可以存在于 Blender 文件内部,而不必作为单独的文件。

你可能认为我们必须把它保存成文件,因为我们以后想在 WebGL 中使用它,但实际上这张贴图并不是我们要使用的最终贴图。

如果你还记得,我们选择勾选了 32-bit float。这让贴图数据比普通贴图精确得多。从某种意义上说,我们做了一张 HDR 贴图。HDR 贴图的问题是它们太重了。

问题在于,我们为什么需要这张 HDR 贴图?我们稍后会回答这个问题。目前,我们把场景 bake 进一张 HDR 贴图,以保留所有数据。

不过,就本课而言,我们想把这张图像保存成一个单独的文件。在 UV Editor 区域顶部,进入 Image > Save As:

应该会弹出一个保存窗口。选择 Radiance HDR 作为 File Format,并把名字改成 baked.hdr。确保保存到与你的 .blend 文件相同的文件夹里:

我们选择了 Radiance HDR 作为 File Format,但其他一些格式也能支持高精度贴图,比如 OpenEXR。不过,文件会变得非常大。

如果你打开 UV Editor 的右侧菜单(将鼠标悬停在该区域时按 N),在 Image 标签页里,你应该会看到贴图现在是同一文件夹里的 baked.hdr 文件:

如果你想分享你的 .blend 文件,或者把它移到另一个文件夹,你就必须把 baked.hdr 文件一起带上。

准备 material

我们几乎准备好 bake 了。因为我们的项目里可能有多张贴图,我们需要一种方式来告诉 Blender,我们创建的那张贴图就是每个对象要 bake 进去的那张。这个信息必须在每个 material 上都提供。

我们可以从地板开始。

选中地板。

要定义 material 应该 bake 到哪张贴图里,我们需要使用 Shader Editor。取你布局上的一个区域(或新建一个),把它改成 Shader Editor:

这将是 grass material 的 Shader Editor,它使用 node。我们不会深入讲解 node 的细节,因为我们只需要创建一个,然后让它生效即可。

如果你看不到这两个 node,确保区域顶部的 Use Nodes 已勾选:

另外,确保你选中了地板,并且 grass material 已应用到它上面。

要创建一个新 node,将鼠标悬停在 Shader Editor 区域时按 SHIFT + A:

在这里,你可以导航到 Texture > Image Texture

这就是一个 Image Texture node:

点击下拉图像图标,选择我们的 baked 贴图:

就是这样。我们的 material 现在知道自己应该 bake 进 baked 贴图里了。我们不需要把这个 node 连接到另一个 node。我们只需要它在这里。

确保这个 texture node 被选中(它应该有一个白色的外轮廓)。

如果你的 shader 里有多个 texture node,用于 baking 的将是那个处于激活状态的。

另外,我们把 Color Space 保持为 linear。这可能听起来很奇怪,因为我们学过 sRGB 能带来更好的颜色管理,但别忘了这仍然是一张 HDR 贴图,我们不会直接在 WebGL 中使用它。

Bake 地板

终于到做第一次 bake 的时候了。

首先,

在地板仍被选中的情况下,在 Properties 区域中进入 Render Properties 标签页,然后进入 Bake 部分:

如果你看不到这个部分,你用的很可能是 Eevee。把 Render Engine 改成 Cycles。

Bake 按钮会启动 baking 过程。先别点它,因为我们需要调整一些参数。

Bake Type 菜单让我们选择想要 bake 的内容。例如,这里就是我们本可以创建 Ambient Occlusion 贴图的地方。让它保持为 Combined,以便 bake 所有内容。

View From 将决定渲染每个表面时 camera 应该在哪里。这对反射可能有相当大的影响。在我们的例子里,由于 material 的粗糙度,我们看不到太多反射,不过我们想要尽可能接近之前做的渲染,所以我们会选择 Active Camera。

Margin 属性让我们控制 baking 会从它本该填充的区域溢出多少。我们暂时保留 16 px。如果我们看到 bake 出来的 island 与相邻的重叠了,就可以减小 margin。

同样在 Margin 中,Type 属性将决定 margin 是包含相邻面的像素,还是延伸现有的面。我们使用 Extend,它在 WebGL 中使用时通常能得到更干净的边缘。

Clear Image 属性会在我们每次 bake 时擦除贴图中的当前图像。因为我们不会一次性做完所有 baking,所以取消勾选它。

在 bake 之前,我们必须选择一个 Sampling 质量。向上滚动到 Sampling > Render 部分。

把 Samples 设为 128,这可能听起来偏低,但这是一张相当大的贴图,我们不想为了等渲染完成而花上几个小时。

同时停用 Denoise,因为我们稍后会在最终 bake 出来的贴图上应用它。保持它勾选在某些 Blender 版本上可能会导致视觉伪影。

确保你只选中了地板,并且 Texture node 处于激活状态。现在,点击 Bake 按钮并等待。

你可以在 Blender 底部看到进度:

地板是需要渲染的最大、耗时最长的部分,但如果你想加速这个过程,可以把 Sampling 改成 128,效果应该已经足够好了。

这就是 bake 到贴图上的地板:

如果 baking 已经结束,但你在贴图里看不到结果,这可能是 Blender 的一个 bug。别担心,过程很可能正常完成了。将鼠标悬停在 UV Editor 区域时用 ALT + S 保存图像。然后,点击同一区域右侧菜单中的刷新按钮(按 N 切换菜单):

即使 baking 成功了,现在也是保存图像的好时机。由于在 Blender 中图像是单独的文件,你必须独立地保存图像。如果你试图在图像未保存的情况下离开 Blender,别担心,Blender 会提醒你。

要保存图像,将鼠标悬停在 UV Editor 区域时,按 ALT + S。

Bake 其他对象

现在我们可以对其他对象重复这个过程。先从栅栏开始。

选中栅栏:

添加相同的 Image Texture node,并把它改成 baked 贴图。同时确保这个 node 处于激活状态:

点击 Bake 按钮并等待:

你可以这样继续处理场景中的所有对象。

如果你尝试 bake 树干、斧柄或原木,你会发现贴图已经在 Shader Editor 的 node 中设置好了。这是因为它们共享同一个 material。

你可以尝试一次 bake 多个对象,只要相关的所有 material 都设置了 texture node。

这是最终 bake 出来的贴图:

别忘了同时保存 .blend 文件和图像。

故障排查

如果你看到有些部分重叠了,选中该对象,进入 Edit Mode,选中所有面,然后开始移动 UV 映射,把 island 稍微分开一点。然后对这些部分再次执行 baking 过程。

如果有些 island 看起来异常地黑,你可能是意外翻转了它们的 normal。你需要找到它们并把它们翻转回来。

你可以把它们 bake 在之前 bake 的结果之上。

导出图像

颜色问题

如你所见,颜色全都过曝了。如果你把它和渲染结果相比,颜色会缺少对比度,而且看起来像这样:

就好像它们在渲染中被调过色一样,而事实正是如此。当你在 Blender 中做渲染时,会使用一个名为 Filmic 的颜色管理器。

你可以在 Render Properties 标签页底部的 Color Management 部分找到它:

如果你想测试一下不用 Filmic 的渲染,把 View Transform 改成 Standard,然后用 F12 做一次渲染:

如你所见,我们得到了同样难看、高对比度的颜色。

这告诉我们,在 Blender 中 baking 时,我们丢失了 Filmic。

噪点问题

另一个问题是视觉噪点。当你做渲染时,如果你勾选了 denoise 参数,你会看到一个没有噪点的平滑渲染。

而 baking 时,噪点又回来了:

和 Filmic 一样,Blender 似乎忽略了 denoise 参数。

图像类型问题

最后,我们想要导出一张可以在 Three.js 中使用的压缩图像。我们希望它轻量,并且因为我们不需要透明度,所以可以使用 JPEG。同时,我们想应用 sRGB 编码来提升颜色质量。

但目前,我们手里只有那张花哨的 HDR 图像。

解决方案

所有这些问题都可以用 Blender 的 Compositor 来解决。

Compositor 可以在某个区域内访问。把当前的一个区域(或新建一个)改成 Compositor:

Compositor 使用 node,默认情况下,你应该有一个 Render Layers node 和一个 Composite node:

要告诉 Blender 在渲染时使用这些 node,确保勾选 Compositor 区域顶部的 Use Nodes:

这里的思路是创建一些 node,它们会接收我们的贴图,对它应用 denoise,然后应用 Filmic。接着我们通过把它发送到 Composite node 来输出那张贴图到渲染结果。

先用 SHIFT + A 创建一个 Image node:

用下拉菜单把图像改成我们的 baked:

正常情况下,你应该能在 node 预览中看到你的贴图,但这个功能有时会有 bug。保存所有内容并重新打开,就能看到预览:

现在在 Image node 的右侧创建一个 Denoise node:

保留默认参数:

把 Image node 的 Image 输出连接到 Denoise node 的 Image 输入:

把这个 Denoise 输出连接到 Composite 输入:

但 Filmic 在哪里呢?你可能会问。

只要你在渲染参数里设置好了它,Filmic 就会自动被应用:

做 compositing 就像是做渲染一样。但我们不想渲染场景,我们想通过我们创建的 node 来渲染我们的图像。要停用默认的场景渲染,选中 Render Layers 并按 M 把它“静音”。

它应该会显示为灰色:

如果你想再次做经典渲染,你必须把我们创建的那两个 node 静音,取消静音 Render Layers,并把这最后一个连接到 Composite。

我们还需要修改渲染的分辨率,让它和贴图分辨率一致。

进入 Output Properties,把分辨率改成 4096x4096:

最后,用 F12 渲染。

这个操作应该不会花太长时间,你应该能看到一张漂亮的渲染,颜色正确且没有噪点:

在渲染窗口打开的情况下,将鼠标悬停在它上面时按 ALT + S 来保存它。

把 File Format 改成 JPEG,把质量稍微降低一点(75% 应该就够了),并把它命名为 baked.jpg:

把它保存到你想要的地方。我们稍后会在 Three.js 中使用它。

导出模型

我们需要对模型应用一些修改,以便进一步优化它。但我们现在不会这么做,因为我们想亲眼看到把它导入 Three.js 时出现的问题。这有助于我们更好地理解为什么要做这些优化。

目前,我们就简单地导出整个场景。

让所有集合都可以选中,但 others 集合除外(连 emissions 集合也要设为可选中):

在 Object Mode 下,用 A 选中所有东西:

现在导出为 glTF 2.0:

以下是导出参数:

还有一些补充说明:

把你的文件命名为 portal.glb,并把它和你的 baked.jpg 文件放在一起。

现在我们同时有了 baked.jpg 文件和 portal.glb 文件。在下一课中,我们会把它们导入 Three.js,并进一步优化模型。